/**   
 * @Title: RemoteImageWOC.java 
 * @Package net.gdface.service.search 
 * @Description: TODO 
 * @author guyadong   
 * @date 2015年5月13日 下午5:17:37 
 * @version V1.0   
 */
package net.gdface.service.search;

import net.facelib.u4fdb.localdb.UrlBean;
import net.gdface.httpclient.HostManager;
import net.gdface.service.client.FetchImage;
import net.gdface.service.client.SaveImage;
import net.gdface.service.client.Status;
import net.gdface.service.client.WorkDataJSON;
import net.gdface.utils.Assert;
import net.gdface.utils.Judge;
import net.gdface.worker.QueueManager;
import net.gdface.worker.RetryException;
import net.gdface.worker.WorkData;

import org.apache.http.StatusLine;
import org.apache.http.concurrent.FutureCallback;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 图像数据下载工作对象<br>
 * 实现{@link org.apache.http.concurrent.FutureCallback}接口<br>
 * 被 {@link org.apache.http.impl.nio.client.CloseableHttpAsyncClient}异步调用<br>
 * 下载完成时({@link #onValidImage()})的图像数据被加入 {@link #saveQueue}队列<br>
 * 如果下载失败，如果需要重试({@link #onRetry()})则把工作对象加入 {@link #downloadQueue}队列
 * 
 * @author guyadong
 *
 */
public class RemoteImageWOC extends WorkDataJSON implements FutureCallback<org.apache.http.HttpResponse> {
	private static final Logger logger = LoggerFactory.getLogger(RemoteImageWOC.class);
	public static final long RETYR_INTERVAL_MILLS = 20 * 1000;

	/**
	 * 下载任务队列管理器
	 */
	private static QueueManager<RemoteImageWOC> downloadQueue;
	/**
	 * 保存任务队列管理器
	 */
	private static QueueManager<WorkDataJSON> saveQueue;
	private static SaveImage saveProcessor;

	public static void set(QueueManager<RemoteImageWOC> downloadQueue, QueueManager<WorkDataJSON> saveQueueManager, FetchImage saveProcessor) {
		Assert.notNull(downloadQueue, "downloadQueue");
		Assert.notNull(saveQueueManager, "saveQueue");
		Assert.notNull(saveProcessor, "saveProcessor");
		RemoteImageWOC.downloadQueue = downloadQueue;
		RemoteImageWOC.saveQueue = saveQueueManager;
		RemoteImageWOC.saveProcessor = saveProcessor;
	}


	public RemoteImageWOC(JSONObject json) {
		super(json);
	}

	@Override
	public void failed(Exception ex) {
		RemoteImage rmi = this.getVariables(VAR_REMOTEIMAGE);
		HostManager.getInstance().hitInc(this.getURI(), false);
		try{
			throw ex;
		} catch (Exception e) {
			rmi.onFailed(e);	
			UrlBean urlBean=this.getVariables(VAR_URLBEAN);
			assert null!=urlBean;
			urlBean.setExp(rmi.getException());
			urlBean.setStatus(rmi.getStatus().name());
		}
		
		boolean retry=rmi.isRetryed();
		if (!retry) {
			onRetry();
		} 
		onFinished(retry);//需要重试时不保存URL状态到数据库
	}

	/**
	 * 在{@link JSONObject}对象中设置重试标志字段,并将工作对象加入延迟队列
	 */
	private void onRetry() {
		try {
			//在JSONObject对象中置入重试标志以及重间隔
			getJson().put(ImgJsonDecoder.KEY_RETRY, true);
			//getJson().put(ImgJsonDecoder.KEY_INTERVAL, DownloadWorker.RETYR_INTERVAL_MILLS);
		} catch (JSONException je) {
			throw new RuntimeException(je);
		}
		// 重新加入延迟工作队列，重试
		downloadQueue.push(this, RemoteImageWOC.RETYR_INTERVAL_MILLS);
		RemoteImage rmi=this.getVariables(VAR_REMOTEIMAGE);
		logger.debug("{} RETRY:{} {}",this.getClass().getSimpleName(),rmi.getException(),getURI());
	}

	@Override
	public void cancelled() {
		logger.warn("CANCELED {}",this.getURI());
		onFinished(false);
	}

	@Override
	public void completed(org.apache.http.HttpResponse result) {
		RemoteImage rmi = this.getVariables(VAR_REMOTEIMAGE);

		boolean finished = true;
		try {
			StatusLine status = result.getStatusLine();
			//检查状态码，返回正常200才进行图像有效性检查
			if (null == status || 200 == status.getStatusCode()) {
				rmi.onCompleted(result);
				if (rmi.isValidImage()) {
					// 加入保存队列，这时工作未结束，所以不能调用onFinished()
					onValidImage();
					finished = false;
				}
			} else{
				rmi.setStatus(Status.NOTIMAGE);
				if (!rmi.isRetryed())
					throw new RetryException();
			}
		} catch (RetryException e) {
			onRetry();
		} finally {
			onFinallyComplete(rmi,finished);
		}
	}

	private void onFinallyComplete(RemoteImage rmi,boolean finished){
		// 状态为Status.FAIL_DOWNLOAD时，视为访问失败
		UrlBean urlBean=this.getVariables(VAR_URLBEAN);
		urlBean.setStatus(rmi.getStatus().name());
		if(!Judge.isEmpty(rmi.getException()))
			urlBean.setExp(rmi.getException());
		HostManager.getInstance().hitInc(getURI(), Status.FAIL_DOWNLOAD != rmi.getStatus());
		if (finished)
			onFinished(rmi.isRetryed());
	}
	/**
	 * 当图像有有效图片时，将当前对象加入保存队列
	 */
	public void onValidImage() {
		saveQueue.push(this,0);
	}

	/**
	 * 保存结果到数据库, 将当前对象从工作对象管理器中删除
	 * 
	 * @param save
	 *            是否保存结果到数据库
	 */
	private void onFinished(boolean save) {
		if (save){			
			saveProcessor.recordStatus(this);
		}
		WorkData.WOKING_DATA.remove(this);
	}
}
